/* ---------------------------------------------------------------------------
** main.cpp
** Main file for a server the receives an unordered list of data and sends
** a sorted list back
**
** Build Instructions:  Build and launch order have been set in solution properites
** Hit F7 to build solution, then F5 to run it.  Server and client will launch in their
** own separate windows.
**
** Author:	Patrick Montgomery
** Course:	SE 558
** Date:	Oct 6th, 2009
** -------------------------------------------------------------------------*/


#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <list>
#include "../SerializerLib/Serializer.h"

#pragma comment(lib,"ws2_32.lib")
			
using namespace std;


int main()
{
	//----------------------------------------------------
	// Add your magic here
	//----------------------------------------------------
	WSADATA wsaData;
	PCSTR SERVER_PORT = "16667";
	SOCKET ListenSocket = INVALID_SOCKET;
	SOCKET ClientSocket = INVALID_SOCKET;
	list<int>clientData;
	struct addrinfo hints;
	struct addrinfo *result = NULL;
	const int DEFAULT_BUFLEN = 512;
	int bytesRecv = 0;
	int recvbuflen = DEFAULT_BUFLEN;
    char* recvbuf =  new char[DEFAULT_BUFLEN];
	

	// Initialize Winsock
	if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
	{
		std::cout << "WSAStartup failed.\n";
		return 1;
	}


	ZeroMemory(&hints, sizeof (hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	hints.ai_flags = AI_PASSIVE;

	// Resolve the local address and port to be used by the server
	if(getaddrinfo(NULL, SERVER_PORT, &hints, &result) != 0)
	{
		std::cout << "getaddrinfo failed.\n";
		WSACleanup();
		return 1;
	}

	
	// Create a socket
	ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);

	if (ListenSocket == INVALID_SOCKET) 
	{
		std::cout << "Socket creation failed.\n";
		freeaddrinfo(result);
		WSACleanup();
		return 1;
	}

	// Bind the socket to the adapter and port
	if (bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen) == SOCKET_ERROR) 
	{
		std::cout << "bind failed.\n";
		freeaddrinfo(result);
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}
	
	// Listen on the socket
	if ( listen( ListenSocket, SOMAXCONN ) == SOCKET_ERROR ) 
	{
		std::cout << "listen failed.\n";
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}

	std::cout << "Waiting for incoming connection...\n";
	//Block for connections
	ClientSocket = accept(ListenSocket, NULL, NULL);
	if (ClientSocket == INVALID_SOCKET) {
		std::cout << "accept failed.\n";
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}

	std::cout << "Client connected!\n";


	
	// Receive until the peer closes the connection
    do {
        bytesRecv = recv(ClientSocket, recvbuf, recvbuflen, 0);
        if ( bytesRecv > 0 )
            printf("Bytes received: %d\n", bytesRecv);
        else if ( bytesRecv == 0 )
            printf("Connection closed\n");
        else
            printf("recv failed with error: %d\n", WSAGetLastError());

    } while( bytesRecv > 0 );

	std::cout << "Unpacking data...\n";
	
	Serializer<int>::unmarshallList(recvbuf, clientData);

	std::cout << "Sorting data...\n";
	clientData.sort();

	const int SEND_BUF_SIZE = ((clientData.size() + 1) * sizeof(int));
	char* sendBuf = new char[SEND_BUF_SIZE];

	
	Serializer<int>::marshallList(clientData, sendBuf);

	std::cout << "Sending sorted data back to client.\n";
    if (send(ClientSocket, sendBuf, SEND_BUF_SIZE, 0) == SOCKET_ERROR) {
        printf("send() failed with error: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return 1;
    }


	std::cout << "Disconnecting...\n";
	if (shutdown(ClientSocket, SD_SEND) == SOCKET_ERROR) {
		printf("shutdown failed: %d\n", WSAGetLastError());
		closesocket(ClientSocket);
		WSACleanup();
		return 1;
	}

	delete sendBuf;
	delete recvbuf;
	closesocket(ClientSocket);
	WSACleanup();

	std::cout << "Connection closed.\n";


	//----------------------------------------------------
	// print and exit
	//----------------------------------------------------
	printf("\n\n");
	system("PAUSE");
	return 0;
}

